package panda.natalia.gothread.suspend.instrument;

import java.util.ServiceLoader;

import panda.natalia.gothread.suspend.Suspendable;
import panda.natalia.gothread.suspend.instrument.MethodDatabase.SuspendableType;

import static panda.natalia.gothread.suspend.GlobalDefine.LAMDA_METHOD_PREFIX;
import static panda.natalia.gothread.suspend.GlobalDefine.SUSPEND_EXECUTION_NAME;

/**
 * a simple framework of java fiber
 *
 * @Author: scpanda2007
 * @Date: 2019/12/4 14:56
 */
public class DefaultSuspendableClassifier implements SuspendableClassifier{

    private final ServiceLoader<SuspendableClassifier> loader;
    private final SuspendableClassifier simpleClassifier;

    public DefaultSuspendableClassifier(ClassLoader classLoader){
        this.loader = ServiceLoader.load(SuspendableClassifier.class, classLoader);
        this.simpleClassifier = new SimpleSuspendableClassifier(classLoader);
    }

    @Override
    public SuspendableType isSuspendable(MethodDatabase db, String sourceName, String sourceDebugInfo, boolean isInterface, String className, String superClassName, String[] interfaces, String methodName, String methodDesc, String methodSignature, String[] methodExceptions) {
        SuspendableType st;

        try {
            for(SuspendableClassifier sc : loader){
                st = sc.isSuspendable(db, sourceName, sourceDebugInfo, isInterface, className, superClassName, interfaces, methodName, methodDesc, methodSignature, methodExceptions);
                if(st != null){
                    return st;
                }
            }

            st = simpleClassifier.isSuspendable(db, sourceName, sourceDebugInfo, isInterface, className, superClassName, interfaces, methodName, methodDesc, methodSignature, methodExceptions);
            if(st != null) return st;

            if(checkException(methodExceptions)) return SuspendableType.SUSPENDABLE;

            // lambda$ 这一段没看懂 看起来是 suspendable 的判断只是去掉那些不需要 做判断的 函数
            // lambda 因为无法判断, 所以这里自动认为是需要做suspendable 判断处理的
            if(methodName.startsWith(LAMDA_METHOD_PREFIX)) return SuspendableType.SUSPENDABLE;
        } catch (Exception e) {
            e.printStackTrace();
            throw e;
        }

        return null;
    }

    private static boolean checkException(String[] exceptions) {
        if(exceptions == null) return false;
        for(String ex : exceptions){
            if(ex.equals(SUSPEND_EXECUTION_NAME)) return true;
        }
        return false;
    }
}
